<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>手写router</title>
</head>
<body>

<h1>测试路由系统</h1>

<button onclick="history.push('/')">首页</button>
<button onclick="history.push('/about')">关于我</button>
<button onclick="history.replace('/xxx')">替换</button>

<script>
  // 自己写一个路由核心模块

  function createCurrentLocation(base) {
    debugger;
    const {pathname, search, hash} = window.location;
    let pos = base.indexOf('#');
    if (pos > -1) {
      return hash.slice(1) || '/';
    }
    return pathname + search + hash;
  }

  // 自己实现一个路径核心模块
  function buildState(back, current, forward, replaced = false, computedScroll = false) {
    return {
      back,
      current,
      forward,
      replaced,
      scroll: computedScroll ? {left: window.pageXOffset, top: window.pageYOffset} : {},
      position: window.history.length - 1
    }
  }

  function useHistoryStateNavigation(base) {
    const currentLocation = {
      value: createCurrentLocation(base)
    }

    const historyState = {
      value: window.history.state
    }

    // 第一次刷新页面 此时没有任何状态 那么我就自己维护一个状态
    if (!historyState.value) {
      changeLocation(currentLocation.value, buildState(null, currentLocation.value, null, true), true)
    }

    function changeLocation(to, state, replaced = false) {
      const pos = base.indexOf('#');
      to = pos > -1 ? base + to : to;
      window.history[replaced ? 'replaceState' : 'pushState'](state, null, to);
      historyState.value = state;
    }

    function push(to, data) {
      // 跳转的时候,我需要做两个状态 一个是跳转前 从哪到哪
      const currentState = Object.assign(
        {},
        historyState.value, // 跳转前的状态
        {forward: to, computedScroll: {left: window.pageXOffset, top: window.pageYOffset}}
      )
      // 本质是没有跳转 只是更新了状态
      changeLocation(currentState.current, currentState, true);
      const nextState = Object.assign(
        {},
        buildState(currentLocation.value, to, null),
        {position: currentState.position + 1},
        data
      );
      // 跳转后 从这到哪
      changeLocation(to, nextState, false);
      currentLocation.value = to;
    }

    function replace(to, data) {
      const currentState = Object.assign(
        {},
        buildState(historyState.value.back, to, historyState.value.forward, true),
        data
      )
      changeLocation(to, currentState, true);
      // 替换后需要将路径变成为现在的路径
      currentLocation.value = to;
    }

    return {
      location: currentLocation,
      state: historyState,
      push,
      replace
    }
  }

  // 前进后退的时候,要更新historyState和currentLocation这2个变量
  function useHistoryListeners(base, historyState, currentLocation) {
    let listeners = [];
    const popStateHandler = ({state}) => {
      const to = createCurrentLocation(base); // 去哪
      const from = currentLocation.value; // 从哪来
      const fromState = historyState.value; // 从哪来状态
      currentLocation.value = to;
      historyState.value = state;
      let isBack = state.position - fromState.position < 0;
      console.log(isBack)
      listeners.forEach(callback => callback(to, from, {isBack}));
    }
    window.addEventListener('popstate', popStateHandler);

    function listen(cb) {
      listeners.push(cb);
    }

    return {
      listen
    };
  }

  function createWebHistory(base = '') {
    // 1.路由系统最基本的包含当前的路径,当前路径下他的状态是什么,需要提供两个切换路径的方法 push replace
    const historyNavigation = useHistoryStateNavigation(base);

    const historyListeners = useHistoryListeners(base, historyNavigation.state, historyNavigation.location);
    const routerHistory = Object.assign({}, historyNavigation, historyListeners);
    Object.defineProperty(routerHistory, 'location', {
      get: () => historyNavigation.location.value,
    })
    Object.defineProperty(routerHistory, 'state', {
      get: () => historyNavigation.state.value,
    })
    return routerHistory;
  }
  
  function createWebHashHistory() {
    return createWebHistory('#');
  }
  
  
  const history = createWebHistory();
  history.listen((to, from, options) => {
    console.log(to, from, options);
  })
</script>

</body>
</html>